package com.bxj.mybatis.generator.plugin;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.codegen.AbstractJavaGenerator;
import org.mybatis.generator.exception.ShellException;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;

public class ApiBuilderPlugin extends PluginAdapter {

    String apiProject;
    String apiPackage;
    String interfacePackage;
    String interfaceProject;
    String beanPackage;
    String apiControllerPackage;
    String projectName;
    String serviceProject;
    String serviceControllerPackage;
    DefaultShellCallback callback = new DefaultShellCallback(true);
    private String webProject;
    private String webPackage;
    VelocityEngine ve = new VelocityEngine();
    private String templates;

    @Override
    public void setProperties(Properties properties) {
        super.setProperties(properties);
        apiProject = properties.getProperty("apiProject"); //$NON-NLS-1$
        apiPackage = properties.getProperty("apiPackage"); //$NON-NLS-1$
        interfacePackage = properties.getProperty("interfacePackage"); //$NON-NLS-1$
        interfaceProject = properties.getProperty("interfaceProject"); //$NON-NLS-1$
        beanPackage = properties.getProperty("beanPackage"); //$NON-NLS-1$
        apiControllerPackage = properties.getProperty("apiControllerPackage"); //$NON-NLS-1$
        projectName = properties.getProperty("projectName"); //$NON-NLS-1$
        serviceProject = properties.getProperty("serviceProject"); //$NON-NLS-1$
        serviceControllerPackage = properties.getProperty("serviceControllerPackage"); //$NON-NLS-1$
        webProject = properties.getProperty("webProject"); //$NON-NLS-1$
        webPackage = properties.getProperty("webPackage"); //$NON-NLS-1$
        templates = properties.getProperty("templates"); //$NON-NLS-1$

        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
//        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath:/templates/");
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        ve.init();
    }

    public boolean validate(List<String> warnings) {
        return true;
    }

    @Override
    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return super.modelExampleClassGenerated(topLevelClass, introspectedTable);
    }

    class ApiGenerator extends AbstractJavaGenerator {

        @Override
        @SuppressWarnings({"rawtypes", "unchecked"})
        public List<CompilationUnit> getCompilationUnits() {
            List answer = new ArrayList();
            String className = new StringBuffer().append("I").
                    append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                    append("Client").toString();
            FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append(apiPackage).append(className).toString());

            FullyQualifiedJavaType fallback = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append(apiPackage + "fallback.").
                            append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                            append("ClientFallBack").toString());

            Interface inter = new Interface(type);
            inter.setVisibility(JavaVisibility.PUBLIC);
            inter.addAnnotation("@FeignClient(path=\"" + introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime() + "\",name = \"server-service\", fallback = " + introspectedTable.getFullyQualifiedTable().getDomainObjectName() + "ClientFallBack.class)");
            inter.addSuperInterface(new FullyQualifiedJavaType("I" + introspectedTable.getFullyQualifiedTable().getDomainObjectName()));
            inter.addImportedType(fallback);
            inter.addImportedType(new FullyQualifiedJavaType(
                    new StringBuffer().
                            append("template_project_package.common.interfaces.I").
                            append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                            toString()));
            inter.addImportedType(new FullyQualifiedJavaType(
                    new StringBuffer().
                            append("org.springframework.cloud.netflix.feign.FeignClient").
                            toString()));


            answer.add(inter);

            TopLevelClass clientFallBack = new TopLevelClass(fallback);
            clientFallBack.setVisibility(JavaVisibility.PUBLIC);
            clientFallBack.addAnnotation("@Component");
            clientFallBack.addSuperInterface(new FullyQualifiedJavaType(className));

            clientFallBack.addImportedType(apiPackage + className);
            clientFallBack.addImportedType("template_project_package.domain.orm.pojo." + introspectedTable.getFullyQualifiedTable().getDomainObjectName());
            clientFallBack.addImportedType("org.springframework.stereotype.Component");
            clientFallBack.addImportedType("org.springframework.web.bind.annotation.PathVariable");
            clientFallBack.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestBody"));
            clientFallBack.addImportedType(new FullyQualifiedJavaType("template_project_package.domain.base.PageInfo"));
            Method method = getQueryMethod(introspectedTable);
            method.addAnnotation("@Override");
            method.addBodyLine("return new " + introspectedTable.getFullyQualifiedTable().getDomainObjectName().
                    toString() + "();");
            clientFallBack.addMethod(method);

            Method method1 = addMethod(introspectedTable);
            method1.addAnnotation("@Override");
            method1.addBodyLine("return null;");
            clientFallBack.addMethod(method1);

            Method method2 = deleteMethod(introspectedTable);
            method2.addAnnotation("@Override");
            method2.addBodyLine("return 0;");
            clientFallBack.addMethod(method2);

            Method method3 = updateMethod(introspectedTable);
            method3.addAnnotation("@Override");
            method3.addBodyLine("return 0;");
            clientFallBack.addMethod(method3);
            answer.add(clientFallBack);

            Method method4 = pageMethod(introspectedTable);
            method4.addAnnotation("@Override");
            method4.addBodyLine("return null;");
            clientFallBack.addMethod(method4);

            Method method5 = searchMethod(introspectedTable);
            method5.addAnnotation("@Override");
            method5.addBodyLine("return null;");
            clientFallBack.addMethod(method5);

            answer.add(clientFallBack);
            return answer;
        }
    }


    class InterfaceJavaGenerator extends AbstractJavaGenerator {

        @Override
        @SuppressWarnings({"rawtypes", "unchecked"})
        public List<CompilationUnit> getCompilationUnits() {
            List answer = new ArrayList();
            String className = new StringBuffer().append("I").
                    append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                    append("Client").toString();
            FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append(apiPackage).append(className).toString());

            FullyQualifiedJavaType fallback = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append(apiPackage + "fallback.").
                            append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                            append("ClientFallBack").toString());


            Interface iInterface = new Interface(new FullyQualifiedJavaType(new StringBuffer().
                    append(interfacePackage).append("I").append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).toString()));
            iInterface.setVisibility(JavaVisibility.PUBLIC);
            iInterface.addImportedType(new FullyQualifiedJavaType(beanPackage + introspectedTable.getFullyQualifiedTable().getDomainObjectName()));
            iInterface.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.PathVariable"));
            iInterface.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestMapping"));
            iInterface.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestMethod"));
            iInterface.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestBody"));
            iInterface.addImportedType(new FullyQualifiedJavaType("template_project_package.domain.base.PageInfo"));
            Method method = getQueryMethod(introspectedTable);
            method.addAnnotation("@RequestMapping(value = \"/query/{id}\", method = RequestMethod.GET)");
            iInterface.addMethod(method);

            Method method1 = addMethod(introspectedTable);
            method1.addAnnotation("@RequestMapping(value = \"/add\", method = RequestMethod.PUT)");
            iInterface.addMethod(method1);


            Method method2 = deleteMethod(introspectedTable);
            method2.addAnnotation("@RequestMapping(value = \"/delete/{id}\", method = RequestMethod.DELETE)");
            iInterface.addMethod(method2);

            Method method3 = updateMethod(introspectedTable);
            method3.addAnnotation("@RequestMapping(value = \"/update\", method = RequestMethod.POST)");
            iInterface.addMethod(method3);
            answer.add(iInterface);
            Method method4 = pageMethod(introspectedTable);
            method4.addAnnotation("@RequestMapping(value = \"/page/{currentPage}/{pageSize}\", method = RequestMethod.GET)");
            iInterface.addMethod(method4);
            Method method5 = searchMethod(introspectedTable);
            method5.addAnnotation("@RequestMapping(value = \"/search/{currentPage}/{pageSize}\", method = RequestMethod.POST)");
            iInterface.addMethod(method5);
            answer.add(iInterface);

            return answer;
        }
    }

    class ApiControllerJavaGenerator extends AbstractJavaGenerator {

        @Override
        @SuppressWarnings({"rawtypes", "unchecked"})
        public List<CompilationUnit> getCompilationUnits() {
            List answer = new ArrayList();
            String className = new StringBuffer().
                    append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                    append("Controller").toString();
            FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append(apiControllerPackage).append(className).toString());

            FullyQualifiedJavaType superInterface = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append("I").
                            append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                            toString());


            TopLevelClass controller = new TopLevelClass(type);
            controller.setVisibility(JavaVisibility.PUBLIC);
//
//                    @RestController
//
//                    @Slf4j
            controller.addAnnotation("@Api(value = \"接口列表\", description = \"接口列表\", tags = \"" + introspectedTable.getTableConfigurationProperty("doc_name") + "\")");
            controller.addAnnotation("@RestController");
            controller.addAnnotation("@RequestMapping(\"/" + introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime() + "\")");

            controller.addSuperInterface(superInterface);

            controller.addImportedType(apiPackage + className);
            controller.addImportedType("template_project_package.domain.orm.pojo." + introspectedTable.getFullyQualifiedTable().getDomainObjectName());
            controller.addImportedType("template_project_package.common.interfaces.I" + introspectedTable.getFullyQualifiedTable().getDomainObjectName());
            controller.addImportedType(apiPackage + "I" + introspectedTable.getFullyQualifiedTable().getDomainObjectName() + "Client");
            controller.addImportedType("javax.annotation.Resource");
            controller.addImportedType("io.swagger.annotations.Api");
            controller.addImportedType("org.springframework.web.bind.annotation.PathVariable");
            controller.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestBody"));
            controller.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestMapping"));
            controller.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RestController"));
            controller.addImportedType(new FullyQualifiedJavaType("template_project_package.domain.base.PageInfo"));

            String fieldName = new StringBuffer().
                    append("i").
                    append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                    append("Client").
                    toString();
            Field field = new Field(fieldName, new FullyQualifiedJavaType(
                    new StringBuffer().
                            append("I").
                            append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                            append("Client").
                            toString()));
            field.addAnnotation("@Resource");
            controller.addField(field);
            Method method = getQueryMethod(introspectedTable);
            method.addAnnotation("@Override");
            method.addBodyLine(String.format("return %s.query(id);", fieldName));
            controller.addMethod(method);

            Method method1 = addMethod(introspectedTable);
            method1.addAnnotation("@Override");
            method1.addBodyLine(String.format("return %s.add(%s);", fieldName, introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime()));
            controller.addMethod(method1);

            Method method2 = deleteMethod(introspectedTable);
            method2.addAnnotation("@Override");
            method2.addBodyLine(String.format("return %s.delete(id);", fieldName));
            controller.addMethod(method2);

            Method method3 = updateMethod(introspectedTable);
            method3.addAnnotation("@Override");
            method3.addBodyLine(String.format("return %s.update(%s);", fieldName, introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime()));
            controller.addMethod(method3);

            Method method4 = pageMethod(introspectedTable);
            method4.addAnnotation("@Override");
            method4.addBodyLine(String.format("return %s.page(currentPage, pageSize);", fieldName));
            controller.addMethod(method4);

            Method method5 = searchMethod(introspectedTable);
            method5.addAnnotation("@Override");
            method5.addBodyLine(String.format("return %s.search(currentPage, pageSize, bean);", fieldName));
            controller.addMethod(method5);
            answer.add(controller);

            return answer;
        }
    }

    public String upperCase(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    class ServiceControllerJavaGenerator extends AbstractJavaGenerator {

        @Override
        @SuppressWarnings({"rawtypes", "unchecked"})
        public List<CompilationUnit> getCompilationUnits() {
            List answer = new ArrayList();
            String className = new StringBuffer().
                    append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                    append("Controller").toString();
            FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append(serviceControllerPackage).append(className).toString());

            FullyQualifiedJavaType superInterface = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append("I").
                            append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                            toString());


            TopLevelClass controller = new TopLevelClass(type);
            controller.setVisibility(JavaVisibility.PUBLIC);
            controller.addAnnotation("@RestController");
            controller.addAnnotation("@RequestMapping(\"/" + introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime() + "\")");

            controller.addSuperInterface(superInterface);

            controller.addImportedType("template_project_package.api.client." + className);
            controller.addImportedType("template_project_package.domain.orm.pojo." + introspectedTable.getFullyQualifiedTable().getDomainObjectName());
            controller.addImportedType("template_project_package.common.interfaces.I" + introspectedTable.getFullyQualifiedTable().getDomainObjectName());
            controller.addImportedType("template_project_package.dao.orm.mapper." + introspectedTable.getFullyQualifiedTable().getDomainObjectName() + "Mapper");
            controller.addImportedType("javax.annotation.Resource");
            controller.addImportedType("org.springframework.web.bind.annotation.PathVariable");
            controller.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestBody"));
            controller.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestMapping"));
            controller.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RestController"));
            controller.addImportedType(new FullyQualifiedJavaType("template_project_package.domain.base.PageInfo"));
            controller.addImportedType(new FullyQualifiedJavaType("template_project_package.domain.orm.pojo." + introspectedTable.getFullyQualifiedTable().getDomainObjectName() + "Example"));

            String fieldName = new StringBuffer().
                    append(introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime()).
                    append("Mapper").
                    toString();
            Field field = new Field(fieldName, new FullyQualifiedJavaType(
                    new StringBuffer().
                            append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                            append("Mapper").
                            toString()));
            field.addAnnotation("@Resource");
            controller.addField(field);
            Method method = getQueryMethod(introspectedTable);
            method.addAnnotation("@Override");
            method.addBodyLine(String.format("return %s.selectByPrimaryKey(id);", fieldName));
            controller.addMethod(method);

            Method method1 = addMethod(introspectedTable);
            method1.addAnnotation("@Override");
            method1.addBodyLine(String.format("if(%s.insert(%s) >= 0) return %s;", fieldName, introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime(), introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime()));
            method1.addBodyLine("return null;");
            controller.addMethod(method1);

            Method method2 = deleteMethod(introspectedTable);
            method2.addAnnotation("@Override");
            method2.addBodyLine(String.format("return %s.deleteByPrimaryKey(id);", fieldName));
            controller.addMethod(method2);

            Method method3 = updateMethod(introspectedTable);
            method3.addAnnotation("@Override");
            method3.addBodyLine(String.format("return %s.updateByPrimaryKeySelective(%s);", fieldName, introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime()));
            controller.addMethod(method3);


            String beanName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();
            Method method4 = pageMethod(introspectedTable);
            method4.addAnnotation("@Override");
            method4.addBodyLine(beanName + "Example example = new " + beanName + "Example();");
            method4.addBodyLine(String.format("long total = %s.countByExample(example);", fieldName));
            method4.addBodyLine("example.setLimitValue1((currentPage - 1) * pageSize);example.setLimitValue2(pageSize);");
            method4.addBodyLine(String.format("return new PageInfo(%s.selectByExample(example), new template_project_package.domain.base.PageRequest(currentPage, pageSize), total);", fieldName));
            controller.addMethod(method4);

            Method method5 = searchMethod(introspectedTable);
            method5.addAnnotation("@Override");
            method5.addBodyLine(beanName + "Example example = new " + beanName + "Example();" + introspectedTable.getFullyQualifiedTable().getDomainObjectName() + "Example.Criteria criteria = example.createCriteria();");
            for (IntrospectedColumn column : introspectedTable.getAllColumns()) {
//                if(0 == column.getFullyQualifiedJavaType().compareTo(PrimitiveTypeWrapper.getStringInstance())) {
//
//
//                } else {
//                    method5.addBodyLine(String.format("if(bean.get%s() != null)", upperCase(column.getJavaProperty())));
//                }
//                introspectedTable.getPrimaryKeyColumns().get(0).
//                introspectedTable.getBaseColumns()
                method5.addBodyLine(String.format("if(bean.get%s() != null && String.valueOf(bean.get%s()).length() != 0)", upperCase(column.getJavaProperty()), upperCase(column.getJavaProperty())));

                method5.addBodyLine(String.format("criteria.and%sEqualTo(bean.get%s());", upperCase(column.getJavaProperty()), upperCase(column.getJavaProperty())));
            }
            method5.addBodyLine(String.format("long total = %s.countByExample(example);", fieldName));
            method5.addBodyLine("example.setLimitValue1((currentPage - 1) * pageSize);example.setLimitValue2(pageSize);");
            method5.addBodyLine(String.format("return new PageInfo(%s.selectByExample(example), new template_project_package.domain.base.PageRequest(currentPage, pageSize), total).pushExtraData(\"bean\", bean);", fieldName));
            controller.addMethod(method5);

            answer.add(controller);

            return answer;
        }
    }

    class WebJavaGenerator extends AbstractJavaGenerator {

        @Override
        @SuppressWarnings({"rawtypes", "unchecked"})
        public List<CompilationUnit> getCompilationUnits() {
            List answer = new ArrayList();
            String className = new StringBuffer().
                    append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                    append("Controller").toString();
            FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append(webPackage).append(className).toString());

            FullyQualifiedJavaType superInterface = new FullyQualifiedJavaType(
                    new StringBuffer().
                            append("I").
                            append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                            toString());

            TopLevelClass controller = new TopLevelClass(type);

            answer.add(controller);
            return answer;

        }
    }

    private Method searchMethod(IntrospectedTable introspectedTable) {
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("search");

        Parameter parameter = new Parameter(PrimitiveTypeWrapper.getIntegerInstance(), "currentPage");
        parameter.addAnnotation("@PathVariable(\"currentPage\")");
        method.addParameter(parameter);
        Parameter parameter2 = new Parameter(PrimitiveTypeWrapper.getIntegerInstance(), "pageSize");
        parameter2.addAnnotation("@PathVariable(\"pageSize\")");
        method.addParameter(parameter2);
        Parameter parameter3 = new Parameter(new FullyQualifiedJavaType(new StringBuffer().
                append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).toString()), "bean");
        parameter3.addAnnotation("@RequestBody");
        method.addParameter(parameter3);
        method.setReturnType(new FullyQualifiedJavaType(new StringBuffer().
                append(String.format("PageInfo<%s>", introspectedTable.getFullyQualifiedTable().getDomainObjectName())).toString()));
        return method;
    }

    private Method pageMethod(IntrospectedTable introspectedTable) {
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("page");

        Parameter parameter = new Parameter(PrimitiveTypeWrapper.getIntegerInstance(), "currentPage");
        parameter.addAnnotation("@PathVariable(\"currentPage\")");
        Parameter parameter2 = new Parameter(PrimitiveTypeWrapper.getIntegerInstance(), "pageSize");
        parameter2.addAnnotation("@PathVariable(\"pageSize\")");
        method.addParameter(parameter);
        method.addParameter(parameter2);
        method.setReturnType(new FullyQualifiedJavaType(new StringBuffer().
                append(String.format("PageInfo<%s>", introspectedTable.getFullyQualifiedTable().getDomainObjectName())).toString()));
        return method;
    }

    public Method getQueryMethod(IntrospectedTable introspectedTable) {
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("query");

        Parameter parameter = new Parameter(PrimitiveTypeWrapper.getIntegerInstance(), "id");
        parameter.addAnnotation("@PathVariable(\"id\")");
        method.addParameter(parameter);
        method.setReturnType(new FullyQualifiedJavaType(new StringBuffer().
                append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).toString()));
        return method;
    }


    public Method addMethod(IntrospectedTable introspectedTable) {
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("add");

        FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                new StringBuffer().
                        append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                        toString());
        Parameter parameter = new Parameter(type, introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime());
        parameter.addAnnotation("@RequestBody");
        method.addJavaDocLine("//" + introspectedTable.getTableConfigurationProperty("doc_name"));
        method.addParameter(parameter);
        method.setReturnType(type);
        return method;
    }

    public Method updateMethod(IntrospectedTable introspectedTable) {
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("update");
        FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                new StringBuffer().
                        append(introspectedTable.getFullyQualifiedTable().getDomainObjectName()).
                        toString());
        Parameter parameter = new Parameter(type, introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime());
        parameter.addAnnotation("@RequestBody");
        method.addParameter(parameter);
        method.setReturnType(PrimitiveTypeWrapper.getIntegerInstance());
        return method;
    }

    public Method deleteMethod(IntrospectedTable introspectedTable) {
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("delete");

        Parameter parameter = new Parameter(PrimitiveTypeWrapper.getIntegerInstance(), "id");
        parameter.addAnnotation("@PathVariable(\"id\")");
        method.addParameter(parameter);
        method.setReturnType(PrimitiveTypeWrapper.getIntegerInstance());
        return method;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(
            IntrospectedTable introspectedTable) {
        try {
            List generatedFile = apiGenerate(introspectedTable);
            generatedFile.addAll(interfaceGenerate(introspectedTable));
            generatedFile.addAll(apiControllerGenerate(introspectedTable));
            generatedFile.addAll(serviceControllerGenerate(introspectedTable));
            generatedFile.addAll(webGenerate(introspectedTable));
            return generatedFile;
        } catch (ShellException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ArrayList<GeneratedJavaFile>();
    }


    private List apiGenerate(IntrospectedTable introspectedTable) throws ShellException {
        if (apiProject == null)
            return new ArrayList();
        ApiGenerator repository = new ApiGenerator();
        repository.setContext(context);
        repository.setIntrospectedTable(introspectedTable);
        List units = repository.getCompilationUnits();
        List generatedFile = new ArrayList();
        GeneratedJavaFile gif;
        for (Iterator iterator = units.iterator(); iterator.hasNext(); ) {
            CompilationUnit unit = (CompilationUnit) iterator.next();
            gif = new GeneratedJavaFile(unit, apiProject,
                    context.getProperty("javaFileEncoding"), context.getJavaFormatter());
            addGeneratedFile(introspectedTable, generatedFile, gif);
        }
        return generatedFile;
    }

    private void addGeneratedFile(IntrospectedTable introspectedTable, List generatedFile, GeneratedJavaFile gif) throws ShellException {
        File directory = callback.getDirectory(gif.getTargetProject(), gif.getTargetPackage());
        File targetFile = new File(directory, gif.getFileName());
        if (!targetFile.exists() || Boolean.parseBoolean(getTableProperty(introspectedTable, "overwrite", "true"))) {
            generatedFile.add(gif);
        }
    }

    private String getTableProperty(IntrospectedTable introspectedTable, String name, String defaultValue) {
        try {
            String overwriteProperties = introspectedTable.getTableConfigurationProperty(name);
            return overwriteProperties == null ? defaultValue : overwriteProperties;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return defaultValue;
    }

    private List interfaceGenerate(IntrospectedTable introspectedTable) throws ShellException {
        if (interfaceProject == null)
            return new ArrayList();
        InterfaceJavaGenerator repository = new InterfaceJavaGenerator();
        repository.setContext(context);
        repository.setIntrospectedTable(introspectedTable);
        List units = repository.getCompilationUnits();
        List generatedFile = new ArrayList();
        GeneratedJavaFile gif;
        for (Iterator iterator = units.iterator(); iterator.hasNext(); ) {
            CompilationUnit unit = (CompilationUnit) iterator.next();
            gif = new GeneratedJavaFile(unit, interfaceProject,
                    context.getProperty("javaFileEncoding"), context.getJavaFormatter());
            addGeneratedFile(introspectedTable, generatedFile, gif);
        }
        return generatedFile;
    }

    private List apiControllerGenerate(IntrospectedTable introspectedTable) throws ShellException {
        if (apiProject == null || apiControllerPackage == null)
            return new ArrayList();
        ApiControllerJavaGenerator repository = new ApiControllerJavaGenerator();
        repository.setContext(context);
        repository.setIntrospectedTable(introspectedTable);
        List units = repository.getCompilationUnits();
        List generatedFile = new ArrayList();
        GeneratedJavaFile gif;
        for (Iterator iterator = units.iterator(); iterator.hasNext(); ) {
            CompilationUnit unit = (CompilationUnit) iterator.next();
            gif = new GeneratedJavaFile(unit, apiProject,
                    context.getProperty("javaFileEncoding"), context.getJavaFormatter());

            addGeneratedFile(introspectedTable, generatedFile, gif);
        }
        return generatedFile;
    }

    private List serviceControllerGenerate(IntrospectedTable introspectedTable) throws ShellException {
        if (serviceProject == null || serviceControllerPackage == null)
            return new ArrayList();

        ServiceControllerJavaGenerator repository = new ServiceControllerJavaGenerator();
        repository.setContext(context);
        repository.setIntrospectedTable(introspectedTable);
        List units = repository.getCompilationUnits();
        List generatedFile = new ArrayList();
        GeneratedJavaFile gif;
        for (Iterator iterator = units.iterator(); iterator.hasNext(); ) {
            CompilationUnit unit = (CompilationUnit) iterator.next();
            gif = new GeneratedJavaFile(unit, serviceProject,
                    context.getProperty("javaFileEncoding"), context.getJavaFormatter());
            addGeneratedFile(introspectedTable, generatedFile, gif);
        }
        return generatedFile;
    }

    private Collection webGenerate(IntrospectedTable introspectedTable) throws ShellException, IOException {
        if (webProject == null || webPackage == null)
            return new ArrayList();

        WebJavaGenerator repository = new WebJavaGenerator();
        repository.setContext(context);
        repository.setIntrospectedTable(introspectedTable);
        List units = repository.getCompilationUnits();
        List generatedFile = new ArrayList();
        GeneratedJavaFile gif;
        for (Iterator iterator = units.iterator(); iterator.hasNext(); ) {
            CompilationUnit unit = (CompilationUnit) iterator.next();
            gif = new GeneratedJavaFile(unit, webProject,
                    context.getProperty("javaFileEncoding"), context.getJavaFormatter());
            File directory = callback.getDirectory(gif.getTargetProject(), gif.getTargetPackage());
            for (String source : templates.split(",")) {
                String targetDirName = introspectedTable.getFullyQualifiedTable().getFullyQualifiedTableNameAtRuntime();
                new File(directory + "/" + targetDirName).mkdir();
                File targetFile = new File(directory + "/" + targetDirName, source);
                if (targetFile.exists() && !Boolean.parseBoolean(getTableProperty(introspectedTable, "overwrite", "true")))
                    continue;
//                Template t = ve.getTemplate("classpath:/" + source, "utf-8");
                Template t = ve.getTemplate("/templates/" + source, "utf-8");
                VelocityContext ctx = new VelocityContext();

                String a = introspectedTable.getAllColumns().get(0).getJavaProperty();
                ctx.put("moduleName", targetDirName);
                ctx.put("fields", introspectedTable.getAllColumns());
                ctx.put("introspectedTable", introspectedTable);

                StringWriter writer = new StringWriter();
                t.merge(ctx, writer);

                PrintWriter fileWriter = new PrintWriter(targetFile);
                fileWriter.println(writer.toString());
                fileWriter.close();
            }

        }
        return generatedFile;
    }
}
